package com.ssky.bean.validator.core;

import com.ssky.bean.validator.core.exception.VldException;
import com.ssky.bean.validator.util.ExpUtil;
import com.ssky.bean.validator.util.RpnExpTools;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * @Author: ssky
 * @Date: 2021/07/30
 * @Description:
 */
public class ValueExpArithmeticExeHandler {

    private final IFieldValueGetHandler fieldValueGetHandler;
    private final String exp;
    //是否存在数学运算
    private final boolean hasArithmetic;

    //表达式拆解后，String或ValueExp
    private final List<Object> variableList = new ArrayList<>();

    public ValueExpArithmeticExeHandler(IFieldValueGetHandler fieldValueGetHandler, String exp) {
        this.fieldValueGetHandler = fieldValueGetHandler;
        this.exp = exp;

        if (StringUtils.isBlank(exp)) {
            this.hasArithmetic = false;
            return;
        }
        if (exp.indexOf("+") != -1 || exp.indexOf("-") != -1 || exp.indexOf("*") != -1
                || exp.indexOf("/") != -1 || exp.indexOf("%") != -1) {
            this.hasArithmetic = true;
            StringTokenizer token = new StringTokenizer(exp, RpnExpTools.Arithmetic_Operator, true);
            int palceHolder = 0;
            while (token.hasMoreTokens()) {
                String fname = token.nextToken().trim();
                if (!ExpUtil.isVariable(fname)) {
                    variableList.add(fname);
                    continue;
                }

                ValueExp vExp = ValueExp.genValueExp(fname);
                variableList.add(vExp);
            }
        } else {
            ValueExp vExp = ValueExp.genValueExp(exp);
            variableList.add(vExp);
            if (vExp == null) {
                throw new VldException("Rule error：The value of the expression(" + exp + ") is null!");
            }
            this.hasArithmetic = false;
        }
    }

    public BigDecimal exe(Object v, Object l, Object b, IValidatorContext context) {
        if (!hasArithmetic) {
            Object exp = variableList.get(0);
            Object vo = fieldValueGetHandler.getExpVaule((ValueExp)exp, v, l, b, context);
            if (vo == null || StringUtils.isBlank(vo.toString())) {
               return null;
            }
            return new BigDecimal(vo.toString());
        } else {
            StringBuilder expSb = new StringBuilder();
            for (int i = 0; i < variableList.size(); i++) {
                Object elem = variableList.get(i);
                if (elem instanceof String){
                   expSb.append(elem);
                }else{
                    Object vo = fieldValueGetHandler.getExpVaule((ValueExp)elem, v, l, b, context);
                    if (vo == null || StringUtils.isBlank(vo.toString())) {
                        return null;
                    }
                    expSb.append(vo.toString());
                }
            }
            BigDecimal rv = RpnExpTools.execByOperation(RpnExpTools.parseByOperation(expSb.toString()));
            return rv;
        }
    }

}
